home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / GW AdaEd 1.4.2 / GWAdaDemos / GWU Demos / elevator.gen < prev    next >
Text File  |  1995-04-09  |  13KB  |  346 lines

  1. -- Simple Elevator Simulation Program
  2. --
  3. -- By Arthur V. Lopes - (C) 1993 
  4.  
  5. -- Package (generic): Elevator_Simulation
  6.  
  7.  
  8. GENERIC
  9.     
  10.     No_Elevators      : Natural;
  11.     Elevator_Capacity : Natural;
  12.     No_Floors         : Natural;
  13.     No_Passengers     : Natural;
  14.  
  15. PACKAGE Elevator_Simulation IS
  16.  
  17.     SUBTYPE Floor_Type     IS Integer RANGE 1..No_Floors;
  18.     SUBTYPE Elevator_Type  IS Integer RANGE 1..No_Elevators;
  19.     SUBTYPE Passenger_Type IS Integer RANGE 1..No_Passengers;
  20.     SUBTYPE Capacity_Type  IS Integer RANGE 0..Elevator_Capacity;
  21. --    SUBTYPE Screen_Depth   IS Integer RANGE 1..24; -- See package screen
  22. --    SUBTYPE Screen_Width   IS Integer RANGE 1..80;
  23.  
  24.     TYPE State IS (Going_Up, Going_Down, Neutral, In_Maintenance);
  25.  
  26.     TYPE Passenger_Waiting IS RECORD
  27.         Id        : Passenger_Type;
  28.         Where     : Floor_Type;
  29.         Go_To     : Floor_Type;
  30.         Time_In   : Natural;
  31.         Direction : State;
  32.         END RECORD;
  33.  
  34.     TASK Generate_Passengers IS
  35.         ENTRY Start;
  36.     END Generate_Passengers;
  37.     
  38.     TASK TYPE Elevator_Task_Type IS
  39.         ENTRY Turn_Key_On(Elevator_Id : Elevator_Type);
  40.     END Elevator_Task_Type;
  41.  
  42.     TASK Control IS
  43.         ENTRY Start;
  44.         ENTRY Open_Doors_Building;
  45.         ENTRY Get_New_Passenger(Passenger : Passenger_Waiting);
  46.         ENTRY At_Floor(Floor_No : Floor_Type; 
  47.                        Unit     : Elevator_Type;
  48.                        Going    : State);
  49.         ENTRY Shut_Down;
  50.     END Control;
  51.  
  52.     Elevator         : ARRAY(Elevator_Type) OF Elevator_Task_Type;    
  53.  
  54.     Total_Wait_Time  : Natural := 0;
  55.     
  56. END Elevator_Simulation;
  57.  
  58.  
  59. WITH Screen_IO; USE Screen_IO; 
  60. WITH Random; USE Random;
  61. WITH Text_IO; USE Text_IO;
  62. WITH My_Int_IO; USE My_Int_IO;
  63. WITH Calendar; USE Calendar;
  64. PACKAGE BODY Elevator_Simulation IS
  65.  
  66.     Passenger_Load   : CONSTANT := 32;
  67.  
  68.     Passengers_To_Go : Natural := No_Passengers;    
  69.  
  70.     Load          : ARRAY(Elevator'RANGE) OF Capacity_Type := (OTHERS => 0);
  71.  
  72.     Stops         : ARRAY(Elevator'RANGE,1..No_Floors) OF Natural;
  73.  
  74.     Activity      : ARRAY(Elevator'RANGE) OF State := (OTHERS => Neutral);
  75.  
  76.     Waiting   : ARRAY(1..No_Passengers) OF Passenger_Waiting;
  77.     No_Waiting: Natural := 0;
  78.  
  79.     In_Unit       : ARRAY(Elevator'RANGE,1..Elevator_Capacity) OF Passenger_Waiting;
  80.     No_In_Unit    : ARRAY(Elevator'RANGE) OF Natural := (OTHERS => 0);
  81.  
  82.     
  83.     FUNCTION Tell_Me_Where_I_Am RETURN Floor_Type IS
  84.     BEGIN
  85.         RETURN Random_Int(Floor_Type'LAST);
  86.     END;
  87.  
  88.     FUNCTION Floor_To_Go(From_Floor : Floor_Type) RETURN Floor_Type IS
  89.         Temp : Floor_Type;
  90.     BEGIN   
  91.         Temp := Random_Int(Floor_Type'LAST);
  92.         WHILE Temp = From_Floor LOOP
  93.             Temp := Random_Int(Floor_Type'LAST);
  94.         END LOOP;
  95.         RETURN Temp;      
  96.     END;
  97.  
  98.     TASK BODY Generate_Passengers IS
  99.         I   : Natural := 0;
  100.         One : Passenger_Waiting;
  101.     BEGIN
  102.         ACCEPT Start;
  103.         While I < No_Passengers LOOP
  104.             IF (Random_Int(181) MOD 2) = 0 THEN
  105.                 I := I + 1;
  106.                 One.Id := I;
  107.                 One.Where := Tell_Me_Where_I_Am;
  108.                 One.Go_To := Floor_To_Go(One.Where);
  109.                 IF One.Where > One.Go_To THEN
  110.                     One.Direction := Going_Down;
  111.                 ELSE
  112.                     One.Direction := Going_Up;
  113.                 END IF;
  114.                 One.Time_In := Natural( Seconds (Clock));
  115.                 Control.Get_New_Passenger(One);
  116.             END IF;
  117.         END LOOP;
  118.     END Generate_Passengers;
  119.  
  120.     TASK BODY Elevator_Task_Type IS
  121.  
  122.         Old_Activity  : State := Neutral;
  123.         My_Id         : Elevator_Type;
  124.         Current_Floor : Natural := 1;  
  125.         Old_Where     : Floor_Type := Floor_Type'FIRST;
  126.         Stoped        : Boolean;
  127.  
  128.         PROCEDURE Move IS
  129.         BEGIN
  130.             CASE Activity(My_Id) IS
  131.                 WHEN Going_Up       => 
  132.                     Current_Floor := Current_Floor + 1;
  133.                     IF Current_Floor > No_Floors THEN
  134.                         Current_Floor := No_Floors;
  135.                         Activity(My_Id) := Going_Down;
  136.                     ELSE
  137.                         DELAY 0.1; -- Time to reach this floor
  138.                     END IF;
  139.                 WHEN Going_Down     => 
  140.                     Current_Floor := Current_Floor - 1;
  141.                     IF Current_Floor < 1 THEN
  142.                         Current_Floor := 1;
  143.                         Activity(My_Id) := Going_Up;
  144.                     ELSE
  145.                         DELAY 0.1; -- Time to reach this floor
  146.                     END IF;
  147.                 WHEN Neutral        =>
  148.                     Activity(My_Id) := Going_Up;
  149.                 WHEN In_Maintenance => 
  150.                     Delay 100.0;
  151.                 WHEN OTHERS =>
  152.                     NULL; 
  153.             END CASE;
  154.             FOR J IN 1..No_Floors LOOP
  155.                 Terminal.WriteAt(Where => (My_ID + 5, J * 2 + 14), What => "  ");
  156.             END LOOP;
  157.             Terminal.WriteAt(Where => (My_Id + 5, Current_Floor * 2 + 14), 
  158.                              What  => Integer'IMAGE(Load(My_Id)));             
  159.         END Move;        
  160.  
  161.     BEGIN
  162.         ACCEPT Turn_Key_On(Elevator_Id : Elevator_Type) DO
  163.             My_Id := Elevator_Id;
  164.         END Turn_Key_On;
  165.         Terminal.WriteAt(Where => (My_Id + 5, 1), 
  166.                          What => "Elevator " & Integer'IMAGE(My_Id));
  167.         --Screen_Mgm.Msg(My_Id + 5, 1,"Elevator " & Integer'IMAGE(My_Id));
  168.         LOOP
  169.             IF Passengers_To_Go <= 0 THEN
  170.                 EXIT;
  171.             END IF;
  172.             Terminal.WriteAt(Where => (My_Id + 5, Old_where     * 2 + 14), 
  173.                              What  => "  ");
  174.             Terminal.WriteAt(Where => (My_Id + 5, Current_Floor * 2 + 14), 
  175.                              What  => Integer'IMAGE(Load(My_Id)));
  176.  
  177.             Stoped := False;
  178.             
  179.             IF No_In_Unit(My_Id) > 0 AND Passengers_To_Go > 0 THEN
  180.                 FOR I IN 1..No_In_Unit(My_Id) LOOP
  181.                     IF In_Unit(My_Id,I).Go_To = Current_FLoor THEN
  182.                         -- Allow passengers to get in / out; Control unit 
  183.                         Control.At_Floor(Current_Floor,My_Id,Activity(My_Id));
  184.                         Stoped := True;
  185.                         EXIT;
  186.                     END IF;
  187.                 END LOOP;
  188.             END IF;
  189.             
  190.             IF NOT Stoped THEN
  191.                 IF Stops(My_Id,Current_Floor) > 0 AND
  192.                    No_In_Unit(My_Id) < Elevator_Capacity THEN
  193.                     Control.At_Floor(Current_Floor,My_Id,Activity(My_Id));
  194.                 END IF;
  195.             END IF;
  196.  
  197.             Move;
  198.  
  199.             IF Activity(My_Id) /= Old_Activity THEN
  200.                 Old_Activity := Activity(My_Id);
  201.                 DELAY 0.2; -- Accelaration / Dessacelaration factor
  202.             END IF;
  203.             Old_Where := Current_Floor;
  204.  
  205.         END LOOP;
  206.  
  207.     END Elevator_Task_Type;           
  208.         
  209.  
  210.     TASK BODY Control IS
  211.         From_Elevator : Elevator_Type;
  212.         From_Floor    : Floor_Type;
  213.         Unit          : Elevator_Type;
  214.         Last_Unit     : Elevator_Type := Elevator'FIRST;
  215.         I             : Natural;
  216.  
  217.         FUNCTION Best_Unit(Current_Floor : Floor_Type) RETURN Elevator_Type IS
  218.             BU  : Elevator_Type := 1;
  219.             DBU : Natural := 0;
  220.             D   : Natural;
  221.         BEGIN
  222. -- For now just do a circular assignment
  223.             IF Last_Unit = Elevator'LAST THEN
  224.                 Last_Unit := Elevator'FIRST;
  225.             ELSE
  226.                 Last_Unit := Last_Unit + 1;
  227.             END IF;
  228.             RETURN Last_Unit;
  229.         END Best_Unit;
  230.  
  231.     BEGIN
  232.         ACCEPT Start;  
  233.         FOR I IN Elevator'RANGE LOOP
  234.             FOR J IN 1..No_Floors LOOP
  235.                 Stops(I,J) := 0;  -- Clear stops
  236.             END LOOP;
  237.             Elevator(I).Turn_Key_On(I);
  238.         END LOOP;
  239.         ACCEPT Open_Doors_Building;
  240.         Generate_Passengers.Start;
  241.         LOOP
  242.             IF Passengers_To_Go <= 0 THEN
  243.                 EXIT;
  244.             END IF;
  245.             SELECT
  246.                 WHEN  No_Waiting < Passenger_Load =>
  247.                 ACCEPT Get_New_Passenger(Passenger : Passenger_Waiting) DO
  248.                     No_Waiting := No_Waiting + 1;
  249.                     Waiting(No_Waiting) := Passenger;
  250.                     Unit := Best_Unit(Waiting(No_Waiting).Where);
  251.                     Stops(Unit,Waiting(No_Waiting).Where) := 
  252.                         Stops(Unit,Waiting(No_Waiting).Where) + 1;
  253.                     Terminal.WriteAt(Where => (2, Passenger.Id * 2 + 14), 
  254.                                      What  => Integer'IMAGE(Passenger.Where));
  255.                     Terminal.WriteAt(Where => (3, Passenger.Id * 2 + 14), 
  256.                                      What  => Integer'IMAGE(Passenger.Go_To));
  257.                     Terminal.WriteAt(Where => (4, Passenger.Id * 2 + 14), 
  258.                                      What  => "  ");
  259.                 END Get_New_Passenger;
  260.             OR  
  261.                 ACCEPT At_Floor(Floor_No : Floor_Type; 
  262.                                 Unit     : Elevator_Type;
  263.                                 Going    : State) DO
  264.                     -- Allow passengers to get out
  265.                     I := 1;
  266.                     WHILE I <= No_In_Unit(Unit) LOOP
  267.                         IF In_Unit(Unit,I).Go_To = Floor_No THEN
  268.                             Total_Wait_Time := Total_Wait_Time +
  269.                                     Natural ( Seconds (Clock)) -
  270.                                     In_Unit(Unit,I).Time_In;
  271.                             Terminal.WriteAt(Where => (4, In_Unit(Unit,I).Id * 2 + 14),
  272.                                              What => " *");
  273.                             -- Put passenger outside elevator
  274.                             FOR J IN I..No_In_Unit(Unit) - 1 LOOP
  275.                                 In_Unit(Unit,J) := In_Unit(Unit,J + 1);
  276.                             END LOOP;
  277.                             No_In_Unit(Unit) := No_In_Unit(Unit) - 1;
  278.                             IF Load(Unit) > 0 THEN
  279.                                 Load(Unit) := Load(Unit) - 1;
  280.                             END IF;
  281.                             FOR J IN 1..No_Floors LOOP
  282.                                 Terminal.WriteAt(Where => (Unit + 5,  J * 2 + 14), 
  283.                                                  What  => "   ");
  284.                             END LOOP;
  285.                             Terminal.WriteAt(Where => (Unit + 5, Floor_No * 2 + 14), 
  286.                                              What  => Integer'IMAGE(No_In_Unit(Unit)));
  287.                             Passengers_To_Go := Passengers_To_Go - 1;
  288.                         ELSE 
  289.                             I := I + 1;
  290.                         END IF;
  291.                     END LOOP;
  292.                     -- Now allow passengers to get in
  293.                     I := 1;
  294.                     WHILE I <= No_Waiting LOOP
  295.                         IF Waiting(I).Where = Floor_No THEN
  296.                             IF No_In_Unit(Unit) < Elevator_Capacity THEN
  297. --                               AND Going = Waiting(I).Direction THEN 
  298.                                 -- Put passenger inside elevator
  299.                                 No_In_Unit(Unit) := No_In_Unit(Unit) + 1;
  300.                                 In_Unit(Unit,No_In_Unit(Unit)) := Waiting(I);
  301.                                 IF Stops(Unit,Floor_No) > 0 THEN
  302.                                     Stops(Unit,Floor_No) := Stops(Unit,Floor_No) - 1;
  303.                                 END IF;
  304.                                 Load(Unit) := Load(Unit) + 1;
  305.                                 FOR J IN 1..No_Floors LOOP
  306.                                     Terminal.WriteAt(Where => (Unit + 5,  J * 2 + 14), 
  307.                                                      What  => "  ");
  308.                                 END LOOP;
  309.                                 Terminal.WriteAt(Where => (Unit + 5, Floor_No * 2 + 14), 
  310.                                                  What  => Integer'IMAGE(Load(Unit)));
  311.                                 FOR J IN I..No_Waiting - 1 LOOP
  312.                                     Waiting(J) := Waiting(J + 1);
  313.                                 END LOOP;
  314.                                 No_Waiting := No_Waiting - 1;
  315.                             ELSE 
  316.                                 I := I + 1;
  317.                             END IF;
  318.                         ELSE
  319.                             I := I + 1;
  320.                         END IF;
  321.                     END LOOP;
  322.                 END At_Floor;
  323.             OR
  324.                 TERMINATE;
  325.             END SELECT;
  326.         END LOOP;
  327.         ACCEPT Shut_Down;
  328.  
  329.     EXCEPTION
  330.         WHEN CONSTRAINT_ERROR =>
  331.             Terminal.WriteAt(Where => (23,1), What => "Unit=" & Integer'IMAGE(Unit));
  332.             Terminal.WriteAt(Where => (23,9), 
  333.                              What  => "N_In_U(U)=" & INTEGER'IMAGE(No_In_Unit(Unit)));
  334.             Terminal.WriteAt(Where => (24,1),
  335.                              What => "P G in I=" & Integer'IMAGE(I));
  336.             Terminal.WriteAt(Where => (24,15), 
  337.                              What  => " No_Waiting=" & Integer'IMAGE(No_Waiting));
  338.             FOR J IN 1..No_Waiting LOOP
  339.                 Terminal.WriteAt(Where => (24,32+J),
  340.                                  What => Integer'IMAGE(Waiting(j).Go_To) & "  ");
  341.             END LOOP;
  342.     END Control;
  343.     
  344. END Elevator_Simulation;
  345.  
  346.